/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package hhf.flex;

import flex.messaging.Destination;
import flex.messaging.MessageBroker;
import flex.messaging.config.ConfigMap;
import flex.messaging.config.ConfigurationException;
import flex.messaging.services.AbstractBootstrapService;
import flex.messaging.services.ServiceAdapter;
import flex.messaging.services.remoting.RemotingDestination;
import hhf.flex.annotations.FlexDestination;
import java.util.Map;
import javax.ejb.Singleton;
import javax.ejb.Stateful;
import javax.naming.Binding;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 *
 * @author François
 */
public class EJBBootStrapService extends AbstractBootstrapService {
	

	private InitialContext ic;
	private String JNDICTX;
	Logger logger = LoggerFactory.getLogger(EJBBootStrapService.class);
	@Override
	public void initialize(String id, ConfigMap properties) {
		String moduleName = null;
		String appName = null;
		try {
			ic = new InitialContext();
			moduleName = (String) ic.lookup("java:module/ModuleName");
			appName = (String) ic.lookup("java:app/AppName");
			JNDICTX = "java:global/"+appName;
		} catch (NamingException ex) {
			logger.error(ex.getMessage(), ex);
		}
		logger.info("initialise ... moduleName : {}, appName : {}", moduleName, appName);
	}

	@Override
	public void start() {
		try {
			Object oCtx = ic.lookup(JNDICTX);
			if (oCtx instanceof Context) {
				Context ctx = (Context) oCtx;
				NamingEnumeration list = ctx.listBindings("");
				while (list != null && list.hasMore()) {
					String itemName = null;
					String className = null;
					try {
						Binding item = (Binding) list.next();
						itemName = item.getName();
						if(!itemName.contains("!")) continue;
						Object ejb = ic.lookup(JNDICTX+"/"+itemName);
						if(ejb.toString().contains("@")) {
							className = ejb.toString().substring(0, ejb.toString().lastIndexOf("@"));
							Class cls = Class.forName(className);
							if(cls.isAnnotationPresent(FlexDestination.class)) {
								createDestination(className, itemName, getScope(cls));
							}
						}else if(ejb.toString().contains("_")) {
							className = ejb.toString().substring(0, ejb.toString().lastIndexOf("_"));
							Class cls = Class.forName(className);
							if(cls.isAnnotationPresent(FlexDestination.class)) {
								createDestination(className, itemName, getScope(cls));
							}
						}
					} catch (NamingException e) {
					} catch (ClassNotFoundException e) {
						logger.error("Error instanciation : "+className);
					}
				}
			}
		} catch (NamingException ex) {
		}
	}

	@Override
	public void stop() {
		MessageBroker messageBroker = MessageBroker.getMessageBroker(null);
		Map<String, Destination> map = messageBroker.getService("remoting-service").getDestinations();
		for(Destination dest : map.values()) {
			dest.stop();
		}
	}
	
	/**
	 * 
	 * @param destination : CityFacade!hhf.worldzones.services.locationServices.cityServices.CityFacadeLocal
	 * @param source : hhf.worldzones.services.locationServices.cityServices.CityFacadeLocal
	 */
	private void createDestination(String destination, String source, String scope) {
		try {
		  //get the default messagebroker
			ConfigMap accessConfig = new ConfigMap();
			ConfigMap serviceAdapterConfig = new ConfigMap();
			MessageBroker messageBroker = MessageBroker.getMessageBroker(null);
			//get the remoting service and add your own destination in my case my destination is called
			RemotingDestination myDestination = (RemotingDestination) messageBroker.getService("remoting-service").createDestination(destination);
			//set the factory property of the destination
//			myDestination.setFactory("ejb");
			//set the source property of the destination
			myDestination.setSource(source);
			myDestination.setScope(scope);
			// attach the default java adapter to your service adapter
			ServiceAdapter serviceAdapter = myDestination.createAdapter("ejb-object");
			//configure some properties to de access config
			accessConfig.addProperty("use-mappings", "true");
			accessConfig.addProperty("method-access-level", "remote");
			serviceAdapterConfig.addProperty("access", accessConfig);
			//we pass the created serviceAdapterConfig and the java adapter to the serviceAdapter
			//so we can initialize our adapter
			serviceAdapter.initialize("ejb-object", serviceAdapterConfig);
			myDestination.setAdapter(serviceAdapter);
			//set the channel to my-amf
			myDestination.addChannel("my-amf");
			myDestination.start();
			logger.info("Dynamic flex\ndestination : {}\nsource : {}\nscope {} : factory ejb", new Object[]{destination, source, scope});
		} catch(ConfigurationException e) {
			logger.error(e.getMessage());
		}
	}

	private String getScope(Class cls) {
		if(cls.isAnnotationPresent(Singleton.class)) return Scope.REQUEST; //APPLICATION; c'est le singleton qui maintien l'etat
		if(cls.isAnnotationPresent(Stateful.class)) return Scope.SESSION; // ici l'ejb doit etre associé à la session
		return Scope.REQUEST; // cas standard
	}

	protected interface Scope {
		public final String REQUEST = "request";
		public final String SESSION = "session";
		public final String APPLICATION = "application";
	}
}
